package org.hackystat.devcathlon.engine.match;

import static org.junit.Assert.*;

import java.util.List;

import javax.xml.datatype.XMLGregorianCalendar;
import org.hackystat.devcathlon.configuration.ConfigurationManager;
import org.hackystat.devcathlon.engine.event.Event;
import org.hackystat.devcathlon.engine.event.EventScore;
import org.hackystat.devcathlon.engine.event.EventScoreManager;
import org.hackystat.devcathlon.engine.event.impl.BestCoverage;
import org.hackystat.devcathlon.engine.team.Team;
import org.hackystat.devcathlon.engine.test.DevcathlonTestHelper;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Test class for Match Manager.
 * 
 * @author Anthony Du
 */
public class TestMatchManager extends DevcathlonTestHelper {
  private static final String teamName = "TestTeam";
  private static final String projectName = "TestTeam";
  private static final String owner = "TeamOwner";
  private Team team;
  private static final String matchName = "TestMatch";
  private Match match;
  private Event event;
  private EventScore score;
  /** The amount of days for streak bonus. */
  private static int dayStreak = 5;
  /** The bonus weight for the holding highest coverage over the dayStreak. */
  private static int streakBonus = 10;
  
  /**
   * Sets up the DevcathlonConfiguration for use in these test cases.
   * 
   * @throws Exception If problems occur setting up the configuration.
   */
  @BeforeClass
  public static void setupConfiguration() throws Exception {
    // Set up the testing DevcathlonConfiguration for the event BestCoverage.
    String eventName = BestCoverage.eventName;
    ConfigurationManager configManager = ConfigurationManager.getInstance();
    configManager.setBaseScoreWeight(eventName, 1);
    configManager.getConfiguration(eventName);
    configManager.setWakeupInterval(eventName, 1440);
    configManager.addProperty(eventName, BestCoverage.dayStreakKey, String.valueOf(dayStreak));
    configManager.addProperty(eventName, BestCoverage.typeOfCoverageKey, "Line");
    configManager.addProperty(eventName, BestCoverage.streakBonusKey, String.valueOf(streakBonus));
  }
  
  /**
   * Setup team and match.
   * @throws Exception when an error occurs.
   */
  @Before
  public void setUp() throws Exception {
    team = makeTeam(teamName, owner, "TeamMember1", "TeamMember2");
    event = new BestCoverage();
    match = addSimpleMatch(matchName, team, getProject(owner, projectName), event);
    // Test the event with no sensor data.
    XMLGregorianCalendar timestamp = Tstamp.makeTimestamp();
    score = event.computeScore(match, team, timestamp);
    EventScoreManager.getInstance().updateEventScore(score);
    match.addScore(event, score);
    MatchManager.getInstance().updateMatch(match);
  }
  
  /**
   * Cleanup team and match.
   * @throws Exception when an error occurs.
   */
  @After
  public void cleanUp() throws Exception {
    deleteMatch(matchName);
    deleteTeam(teamName);
  }
  
  /**
   * Test creating a match.
   */
  @Test
  public void testMatchManager() {
    assertEquals("should be the same match names", 
        match.getName(), MatchManager.getInstance().getMatch(matchName).getName());
    assertEquals("should have one team", 1, match.getTeams().size());
    assertEquals("should have the same num team(s)", match.getTeams().size(), 
        MatchManager.getInstance().getMatch(matchName).getTeams().size());
    for (Team team : match.getTeams()) {
      assertEquals("should be the team name", teamName, team.getName());
    }
  }
  
  /**
   * Test get all matches and teams.
   */
  @Test
  public void testGetAllMatches() {
    List<Match> matches = (List<Match>) MatchManager.getInstance().getAllMatches();
    assertEquals("should only have one match", 1, matches.size());
    for (Match match : matches) {
      for (Team team : match.getTeams()) {
        assertEquals("should be the same team name", teamName, team.getName());
      }
    }
  }
  
  /**
   * Test get match events.
   */
  @Test 
  public void testGetMatchEvents() {
    List<Event> events = match.getEvents();
    assertEquals("should have one event", 1, events.size());
    for (Event event : events) {
      assertEquals("event name should be Best Coverage", BestCoverage.eventName, event.getName());
    }
    // Test event score to event map.
    assertEquals("event name should be Best Coverage", 
        BestCoverage.eventName, match.getEvent(score).getName());
  }
  
  /**
   * Test get match event scores.
   */
  @Test
  public void testGetEventScores() {
    assertEquals("should have one event score", 1, match.getEventScores().size());
    for (EventScore eventScore : match.getEventScores()) {
      assertEquals("event name should be Best Coverage", BestCoverage.eventName, 
          match.getEvent(eventScore).getName());
    }
  }
  
  /**
   * Test updating a match.
   * @exception Exception if an error occurs/
   */
  @Test 
  public void testUpdateMatch() throws Exception {
    match = MatchManager.getInstance().getMatch(matchName);
    // test old match
    assertEquals("should have 1 event score", 1, match.getEventScores().size());
    // update match
    for (EventScore score : match.getEventScores()) {
      score.setBaseScore(100);
      EventScoreManager.getInstance().updateEventScore(score);
    }
//    MatchManager.getInstance().updateMatch(match);
    match = MatchManager.getInstance().getMatch(matchName);
    // test new match
    for (EventScore score : match.getEventScores()) { 
      assertEquals("event score base value is 100", 100, score.getBaseScore());
    }
  }
}
